package com.jfinal.ext.generator;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.jfinal.aop.Before;
import com.jfinal.ext.validator.ActivitiValidator;
import com.jfinal.kit.StrKit;

/**
 * Controller 生成器
 */
public class ControllerGenerator {

    protected String packageTemplate = "package %s.%s;%n%n";
    protected String importTemplate = "import org.apache.commons.lang3.StringUtils;%n%n"
            + "import com.jfinal.plugin.activerecord.Page;%n%n"
            + "import %s.interceptor.AdminInterceptor;%n%n"
            + "import %s.controller.BaseController;%n%n" + "import com.jfinal.aop.Before;"
            + "import com.jfinal.ext.route.ControllerBind;%n"+"import java.util.HashMap;%n" +
            "import java.util.Map;%n" + "import %s.%s.%s;%n%n";
    // "import %s.%s.%s;%n%n";
    protected String classDefineTemplate = "/**%n" + " * %sController, Generated by Robot on " + Constants.DATE_TIME
            + ".%n" + " */%n"
            + "@Before(AdminInterceptor.class)%n"
            + "@ControllerBind(controllerKey = \"/%s\", viewPath = \"/WEB-INF/views/%s/\")%n"
            + "public class %sController extends BaseController {%n%n"
            + "\tprivate final String MODULE_NAME = \"/%s\";%n%n";
    // +"\tprivate %sService %sService = new %sService();%n%n";

    protected String indexTemplate = "%n\tpublic void index() {%n"
            + "\t\tPage<%s> page = %s.dao.page(getParaToInt(\"pageNumber\", 1), getParaToInt(\"pageSize\", 10));%n"
            + "\t\tsetAttr(\"page\", page);%n" + "\t\trender(\"index.html\");%n" + "\t}%n%n";

    protected String dateTimeTemplate = "\t\t\tmodel.set%d(new Date());%n";

    protected String saveTemplate = "\tpublic void save() {%n" + "\t\t%s model = getModel(%s.class, \"%s\");%n"
            + "\t\tboolean isSave = model.get%s() == null;%n%n" + "\t\tif (%s.dao.saveOrUpdate(model, isSave))%n"
            + "\t\t\tredirect(MODULE_NAME);%n" + "\t\telse%n" + "\t\t\trenderError(501);%n" + "\t}%n%n";

    protected String editTemplate = "\tpublic void edit() {%n"
            + "\t\t%s %s = %s.dao.findById(getParaToInt(\"%s\",0));%n" + "\t\tif (%s == null)%n"
            + "\t\t\t%s = new %s();%n%n" + "\t\tsetAttr(\"%s\", %s);%n" + "\t\trender(\"edit.html\");%n" + "\t}%n%n";

    protected String deleteTemplate = "\tpublic void delete() {%n"
            + "\t\tString ids = StringUtils.join(getParaValues(\"ids\"), \",\");%n"
            + "\t\tint ret = %s.dao.batchDelete(ids);%n" + "\t\tif (ret>0) {%n"
            + "\t\t\tajaxJsonSuccessMessage(\"删除成功!\");%n" + "\t\t} else {%n"
            + "\t\t\tajaxJsonErrorMessage(\"删除失败！\");%n" + "\t\t}%n" + "\t}%n%n";

    protected String breadTemplate = "\tprivate String indexTitle = \"%s\";%n"
            + "\tprivate String editTitle = \"编辑\";%n%n"
            + "\tpublic Map<String,String> getPageTitleBread() {%n"
            + "\t\tMap<String,String> pageTitleBread = new HashMap<String,String>();%n"
            + "\t\tpageTitleBread.put(\"indexTitle\", indexTitle);%n"
            + "\t\tpageTitleBread.put(\"editTitle\", editTitle);%n"
            + "\t\treturn pageTitleBread;%n"
            + "\t}%n";

    protected String modelPackageName;
    protected String baseModelPackageName;
    protected String modelOutputDir;
    protected boolean generateDaoInModel = true;

    public ControllerGenerator(String modelPackageName, String baseModelPackageName, String modelOutputDir) {
        if (StrKit.isBlank(modelPackageName))
            throw new IllegalArgumentException("modelPackageName can not be blank.");
        if (modelPackageName.contains("/") || modelPackageName.contains("\\"))
            throw new IllegalArgumentException("modelPackageName error : " + modelPackageName);
        if (StrKit.isBlank(baseModelPackageName))
            throw new IllegalArgumentException("baseModelPackageName can not be blank.");
        if (baseModelPackageName.contains("/") || baseModelPackageName.contains("\\"))
            throw new IllegalArgumentException("baseModelPackageName error : " + baseModelPackageName);
        if (StrKit.isBlank(modelOutputDir))
            throw new IllegalArgumentException("modelOutputDir can not be blank.");

        this.modelPackageName = modelPackageName;
        this.baseModelPackageName = baseModelPackageName;
        this.modelOutputDir = modelOutputDir;
    }

    public void setGenerateDaoInModel(boolean generateDaoInModel) {
        this.generateDaoInModel = generateDaoInModel;
    }

    public void generate(List<TableMeta> tableMetas) {
        System.out.println("Generate Controller ...");
        for (TableMeta tableMeta : tableMetas)
            genModelContent(tableMeta);
        wirtToFile(tableMetas);
    }

    protected void genModelContent(TableMeta tableMeta) {
        StringBuilder ret = new StringBuilder();
        genPackage(tableMeta, ret);
        genImport(tableMeta, ret);
        genClassDefine(tableMeta, ret);
        genIndexMethod(tableMeta, ret);
        genSaveMethod(tableMeta, ret);
        genEditMethod(tableMeta, ret);
        genDeleteMethod(tableMeta, ret);
        genBreadMethod(tableMeta,ret);
        ret.append(String.format("}%n"));
        tableMeta.modelContent = ret.toString();
    }

    protected void genPackage(TableMeta tableMeta, StringBuilder ret) {
        ret.append(String.format(packageTemplate, modelPackageName, "controller"));
    }

    protected void genImport(TableMeta tableMeta, StringBuilder ret) {
        ret.append(String.format(importTemplate,
                /*
                 * modelPackageName.subSequence(0,
                 * modelPackageName.lastIndexOf('.')),
                 */modelPackageName, modelPackageName, modelPackageName, "model", tableMeta.modelName, modelPackageName, "services.impl",
                tableMeta.modelName + "Service"));
        if (tableMeta.validatorInIt != null) {
            if (tableMeta.validatorInIt) {
                ret.append(String.format("import " + baseModelPackageName + ".validator." + tableMeta.modelName + "Validator;%n%n"));
            }
        }
    }

    protected void genClassDefine(TableMeta tableMeta, StringBuilder ret) {
        ret.append(String.format(classDefineTemplate, tableMeta.modelName, tableMeta.modelName.toLowerCase(),
                tableMeta.modelName.toLowerCase(), tableMeta.modelName, tableMeta.modelName.toLowerCase()));
    }

    protected void genIndexMethod(TableMeta tableMeta, StringBuilder ret) {
        ret.append(String.format(indexTemplate, tableMeta.modelName, tableMeta.modelName));
    }

    /*
     * private boolean fillDateTimeColumn(TableMeta tableMeta) { for (ColumnMeta
     * columnMeta : tableMeta.columnMetas) if (columnMeta.name.contains("Time")
     * || columnMeta.name.contains("Date")) return true; return false; }
     */

    protected void genSaveMethod(TableMeta tableMeta, StringBuilder ret) {
        // if (fillDateTimeColumn(tableMeta))
        if (tableMeta.validatorInIt != null) {
            if (tableMeta.validatorInIt) {
                ret.append(String.format("\t@Before(" + tableMeta.modelName + "Validator.class)%n"));
            }
        }
        String getterMethodName = StrKit.firstCharToUpperCase(StrKit.toCamelCase(tableMeta.primaryKey));
        ret.append(String.format(saveTemplate, tableMeta.modelName, tableMeta.modelName, StrKit.firstCharToLowerCase(tableMeta.modelName), getterMethodName,
                tableMeta.modelName));
    }

    protected void genEditMethod(TableMeta tableMeta, StringBuilder ret) {
        ret.append(String.format(editTemplate, tableMeta.modelName, StrKit.firstCharToLowerCase(tableMeta.modelName),
                tableMeta.modelName, tableMeta.primaryKey, StrKit.firstCharToLowerCase(tableMeta.modelName),
                StrKit.firstCharToLowerCase(tableMeta.modelName), tableMeta.modelName,
                StrKit.firstCharToLowerCase(tableMeta.modelName), StrKit.firstCharToLowerCase(tableMeta.modelName)));
    }

    protected void genDeleteMethod(TableMeta tableMeta, StringBuilder ret) {
        ret.append(String.format(deleteTemplate, tableMeta.modelName));
    }
    protected void genBreadMethod(TableMeta tableMeta,StringBuilder ret){
       ret.append(String.format(breadTemplate,StrKit.notBlank(tableMeta.remarks)?tableMeta.remarks:tableMeta.modelName));
    }

    protected void wirtToFile(List<TableMeta> tableMetas) {
        try {
            for (TableMeta tableMeta : tableMetas)
                wirtToFile(tableMeta);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 若 model 文件存在，则不生成，以免覆盖用户手写的代码
     */
    protected void wirtToFile(TableMeta tableMeta) throws IOException {
        File dir = new File(modelOutputDir + File.separator + "controller" + File.separator);
        if (!dir.exists())
            dir.mkdirs();

        String target = modelOutputDir + File.separator + "controller" + File.separator + File.separator
                + tableMeta.modelName + "Controller.java";

        File file = new File(target);
        if (file.exists()) {
            return; // 若 Model 存在，不覆盖
        }

        FileWriter fw = new FileWriter(file);
        try {
            fw.write(tableMeta.modelContent);
        } finally {
            fw.close();
        }
    }
}
